package edu.ustb.gateway.filter;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.Maps;
import com.google.gson.Gson;
import edu.ustb.gateway.entity.InputMessageMq;
import edu.ustb.gateway.entity.MessageMq;
import edu.ustb.gateway.mapper.InputMessageMqMapper;
import edu.ustb.gateway.mapper.MessageMqMapper;
import edu.ustb.gateway.service.GatewayService;
import io.netty.buffer.ByteBufAllocator;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.cloud.gateway.support.ServerWebExchangeUtils;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferFactory;
import org.springframework.core.io.buffer.NettyDataBufferFactory;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpRequestDecorator;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.MultiValueMap;
import org.springframework.util.StreamUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.io.IOException;
import java.io.InputStream;
import java.net.InetSocketAddress;
import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;

/**
 * @author ShiZhe
 * @create 2020-4-10 18:12
 * 监控通过网关路由的ip，生成用户调用信息，并转发给总线
 */
@Slf4j
@Component
public class VisitGlobalFilterRabbitMq implements GlobalFilter, Ordered {

    private final ObjectMapper mapper = new ObjectMapper();
    private final DataBufferFactory dataBufferFactory = new NettyDataBufferFactory(ByteBufAllocator.DEFAULT);

    /**
     * 发送给RabbitMQ的new的java对象
     */
    MessageMq messageMq = new MessageMq();

    /**
     * 从RabbitMQ接收到的java对象
     */
    InputMessageMq inputMessageMq = new InputMessageMq();

    @Autowired
    private GatewayService gatewayService;

    @Autowired
    private MessageMqMapper messageMqMapper;

    @Autowired
    private InputMessageMqMapper inputMessageMqMapper;

    /**
     * askId使用random函数随机生成
     */
    Random random = new Random();
    private Long askId;
    /**
     * 回调地址，从配置文件中读取
     */
    @Value("${spring.cloud.stream.bindings.input.destination}")
    private String callBackUrl;

    /**
     * mp条件查询
     * stringObjectHashMap查询responseId
     */
    HashMap<String, Object> stringObjectHashMap = new HashMap<>();

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        String path = request.getPath().pathWithinApplication().value();
        HttpMethod method = request.getMethod();
        StringBuilder builder = new StringBuilder();
        URI targetUri = exchange.getAttribute(ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR);
        if (HttpMethod.GET.equals(method)) {
            MultiValueMap<String, String> queryParams = request.getQueryParams();
            try {
                builder.append(mapper.writeValueAsString(queryParams));
            } catch (JsonProcessingException e) {
                log.error(e.getMessage(), e);
            }
        } else if (HttpMethod.POST.equals(method)) {
            Flux<DataBuffer> body = request.getBody();
            ServerHttpRequest serverHttpRequest = request.mutate().uri(request.getURI()).build();
            body.subscribe(dataBuffer -> {
                InputStream inputStream = dataBuffer.asInputStream();
                try {
                    builder.append(StreamUtils.copyToString(inputStream, StandardCharsets.UTF_8));
                } catch (IOException e) {
                    log.error(e.getMessage(), e);
                }
            });
            request = new ServerHttpRequestDecorator(serverHttpRequest) {
                @Override
                public Flux<DataBuffer> getBody() {
                    return Flux.just(dataBufferFactory.wrap(builder.toString().getBytes(StandardCharsets.UTF_8)));
                }
            };
        }
        InetSocketAddress remoteAddress = request.getRemoteAddress();


        // 信息发送过滤



        //判断消费者唯一识别id是否存在，否则未登录，游客无法访问服务
        System.out.println("执行了消费者唯一识别id是否存在的判断");

        //1.获取消费者id值，consumer_id
        String consumerId1 = exchange.getRequest().getQueryParams().getFirst("consumerId");

        //2.判断是否存在
        if (consumerId1 == null || consumerId1.isEmpty()) {
            ServerHttpResponse response = exchange.getResponse();

            // 3.如果不存在，封装错误信息
            Map<String, Object> responseData = Maps.newHashMap();
            responseData.put("code", 401);
            responseData.put("message", "非法请求");
            responseData.put("cause", "Consumer_id is empty");

            try {
                // 将信息转换为 JSON
                ObjectMapper objectMapper = new ObjectMapper();
                byte[] data = objectMapper.writeValueAsBytes(responseData);

                // 输出错误信息到页面
                DataBuffer buffer = response.bufferFactory().wrap(data);
                response.setStatusCode(HttpStatus.UNAUTHORIZED);
                response.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
                return response.writeWith(Mono.just(buffer));
            } catch (JsonProcessingException e) {
                e.printStackTrace();
            }
        }

        //4.如果存在,继续执行，并将得到的消费者id，有string转为long
        Long consumerId = Long.valueOf(consumerId1);



        //判断合约地址是否存在，否则无法访问服务
        System.out.println("执行了合约地址是否存在的判断");

        //1.获取消费者id值，consumer_id
        String contractId = exchange.getRequest().getQueryParams().getFirst("contractId");

        //2.判断是否存在
        if (contractId == null || contractId.isEmpty()) {
            ServerHttpResponse response = exchange.getResponse();

            // 3.如果不存在，封装错误信息
            Map<String, Object> responseData = Maps.newHashMap();
            responseData.put("code", 401);
            responseData.put("message", "非法请求");
            responseData.put("cause", "Contract_id is empty");

            try {
                // 将信息转换为 JSON
                ObjectMapper objectMapper = new ObjectMapper();
                byte[] data = objectMapper.writeValueAsBytes(responseData);

                // 输出错误信息到页面
                DataBuffer buffer = response.bufferFactory().wrap(data);
                response.setStatusCode(HttpStatus.UNAUTHORIZED);
                response.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
                return response.writeWith(Mono.just(buffer));
            } catch (JsonProcessingException e) {
                e.printStackTrace();
            }
        }
        //4.如果存在,继续执行


        //获取endpoint_service的值
        //根据字符串的indexOf方法找到在字符串中第一次出现的/字符位置
        int index= path.indexOf("/");
        //再根据 index+1的位置开始查找第一次出现%的位置，这样就找出第二次出现%字符的位置了
        int index2=path.indexOf("/",index+1);
        //最后根据第一次出现的位置+1 和 第二次出现%的位置来截取字符串
        String endpointService = path.substring(index+1, index2);



        //messageMQ对象填充
        messageMq.setAskId(random.nextLong());
        askId = messageMq.getAskId();
        System.out.println(askId);
        messageMq.setConsumerId(consumerId);
        messageMq.setEndpointService(endpointService);
        messageMq.setActionParams(builder.toString());
        messageMq.setServiceAction(path);
        messageMq.setContractId(contractId);
        messageMq.setCallbackUrl(callBackUrl);

        // 插入数据库
        messageMqMapper.insert(messageMq);

        // messageMQ对象转成Json
        Gson gson2 =new Gson();
        String json = gson2.toJson(messageMq);
        System.out.println(json);

        //发送给RabbitMQ
        gatewayService.send(json);









        // 信息接收过滤

        // 寻找askId对应的responseId
        System.out.println("寻找askId对应的responseId");

        label:while (true) {
            Long start = System.currentTimeMillis();
            stringObjectHashMap.put("response_id",askId);
            List<InputMessageMq> inputMessageMqs = inputMessageMqMapper.selectByMap(stringObjectHashMap);
            if (null == inputMessageMqs || inputMessageMqs.size() ==0){

            }else {
                inputMessageMq = inputMessageMqs.get(0);
                System.out.println(inputMessageMq.toString());
                break label;
            }
            Long start1 = System.currentTimeMillis() - start;
            if(start1.longValue() > 30000) {
                ServerHttpResponse response = exchange.getResponse();
                Map<String, Object> responseData = Maps.newHashMap();
                responseData.put("code", 404);
                responseData.put("message", "请求超时");
                responseData.put("cause", "time is out！please flash！");
                try {
                    // 将信息转换为 JSON
                    ObjectMapper objectMapper = new ObjectMapper();
                    byte[] data = objectMapper.writeValueAsBytes(responseData);
                    // 输出错误信息到页面
                    DataBuffer buffer = response.bufferFactory().wrap(data);
                    response.setStatusCode(HttpStatus.UNAUTHORIZED);
                    response.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
                    return response.writeWith(Mono.just(buffer));
                } catch (JsonProcessingException e) {
                    e.printStackTrace();
                }
            }
        }

        // 判断result值是否为200
        System.out.println("执行了result值的判断");

        Integer result = inputMessageMq.getResult();
        Integer trueResult = 200;
        if (!result.equals(trueResult)) {
            ServerHttpResponse response = exchange.getResponse();
            Map<String, Object> responseData = Maps.newHashMap();
            responseData.put("code", 401);
            responseData.put("message", "非法请求");
            responseData.put("cause", "result is error");
            try {
                // 将信息转换为 JSON
                ObjectMapper objectMapper = new ObjectMapper();
                byte[] data = objectMapper.writeValueAsBytes(responseData);

                // 输出错误信息到页面
                DataBuffer buffer = response.bufferFactory().wrap(data);
                response.setStatusCode(HttpStatus.UNAUTHORIZED);
                response.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
                return response.writeWith(Mono.just(buffer));
            } catch (JsonProcessingException e) {
                e.printStackTrace();
            }
        }

        // 输出inputMessageMq的content
        System.out.println(inputMessageMq.getContent());




////请求路径:/product/1,远程IP地址:/0:0:0:0:0:0:0:1:62909,请求方法:GET,请求参数:{},目标URI:http://10.147.20.22:12345/product/1,响应码:200 OK
//        return chain.filter(exchange.mutate().request(request).build()).then(Mono.fromRunnable(() -> {
//            ServerHttpResponse response = exchange.getResponse();
//            HttpStatus statusCode = response.getStatusCode();
//            log.info("请求路径:{},远程IP地址:{},请求方法:{},请求参数:{},目标URI:{},响应码:{}",
//                    path,remoteAddress, method, builder.toString(), targetUri, statusCode);
//        }));


//        // 继续向下执行
        return chain.filter(exchange);
    }

    /**
     * 指定过滤器的执行顺序 , 返回值越小,执行优先级越高
     */
    @Override
    public int getOrder() { //指定过滤器的执行顺序，返回值越小，执行优先级越高
        return 0;
    }
}
